﻿using System;
using System.Net;
using System.Runtime.Serialization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace Yek.BI.Data
{
    [DataContract]
    public class Event
    {
        [DataMember(Name = "id")]
        public string Id { get; set; }

        [DataMember(Name = "name")]
        public string Name { get; set; }

        [DataMember(Name = "className")]
        public string ClassName { get; set; }

        [DataMember(Name = "codeType")]
        public string CodeType { get; set; }

        [DataMember(Name = "eventPoint")]
        public string EventPoint { get; set; }

        [DataMember(Name = "comment")]
        public string Comment { get; set; }

        [DataMember(Name = "fields")]
        public Field[] Fields { get; set; }

        private string hfile;
        public string HFile
        {
            get
            {
                if (hfile == null)
                    CreateCode();
                return hfile;
            }
            set
            {
                hfile = value;
            }
        }

        private string mfile;
        public string MFile
        {
            get
            {
                if (mfile == null)
                    CreateCode();
                return mfile;
            }
            set
            {
                mfile = value;
            }
        }

        public string WinPhoneFile
        {
            get
            {
                return CreateWinPhoneCode();
            }
        }
        public string FileName
        {
            get
            {
                return string.Format("{0}", this.ClassName);
            }
        }

        private string CreateWinPhoneCode()
        {

            System.Text.StringBuilder sb = new System.Text.StringBuilder();

            //System.Text.StringBuilder other = new System.Text.StringBuilder();//额外文本

            sb.AppendLine("using System;");
            sb.AppendLine("using System.Text;");
            sb.AppendLine("using System.Collections.Generic;");
            sb.AppendLine();
            sb.AppendLine("namespace YEK.BI.Event");
            sb.AppendLine("{");
            sb.AppendLine("\t/// <summary>");
            sb.AppendLine("\t/// " + Name + "事件");
            sb.AppendLine("\t/// </summary>");
            sb.AppendLine(string.Format("\t{1} class {0}Event : BaseEvent", ClassName, CodeType == "APP" ? "public" : "internal"));
            sb.AppendLine("\t{");
            sb.AppendLine(string.Format("\t\tpublic {0}Event()", ClassName));
            sb.AppendLine("\t\t{");
            sb.AppendLine(string.Format("\t\t\tbase.EventId = {0};", Id));
            sb.AppendLine("\t\t}");
            //生成字段
            CreateClass(sb, this.Fields, 0);

            sb.AppendLine();
            //生成方法体
            sb.AppendLine("\t\tpublic override void WriteLog(System.IO.Stream stream)");
            sb.AppendLine("\t\t{");
            sb.AppendLine("\t\t\tbase.WriteLog(stream);");
            WriteLog(sb, this.Fields, 0);
            sb.AppendLine("\t\t}");

            sb.AppendLine("\t}");

            sb.AppendLine("}");
            return sb.ToString();
        }

        private static void WriteLog(System.Text.StringBuilder sb, Field[] fields, int index, bool isNestClass = false)
        {
            string temp = "\t\t\t";

            for (int i = 0; i < index; i++)
            {
                temp += "\t";
            }

            foreach (var f in fields)
            {
                string name = f.Name;
                if (isNestClass)
                    name = "item." + f.Name;
                sb.AppendLine(string.Format(temp + "//加入{0}", f.Name));

                switch (f.Type)
                {
                    case "M":
                    case "P":
                    case "S":
                        sb.AppendLine(string.Format(temp + "WriteString({0}, stream);", name));
                        break;
                    case "I":
                        sb.AppendLine(string.Format(temp + "WriteInt({0}, stream);", name));
                        break;
                    case "E":
                        sb.AppendLine(string.Format(temp + "WriteByte({0}, stream);", name));
                        break;
                    case "F":
                        sb.AppendLine(string.Format(temp + "WriteShort({0}, stream);", name));
                        break;
                    case "K":
                        {
                            sb.AppendLine(string.Format(temp + "//加入loop循环"));
                            sb.AppendLine(string.Format(temp + "WriteShort((short){0}Array.Length, stream);", f.Name));
                            sb.AppendLine(string.Format(temp + "foreach (var item in {0}Array)", f.Name));
                            sb.AppendLine(temp + "{");
                            WriteLog(sb, f.Loop, index + 1, true);
                            sb.AppendLine(temp + "}");
                        }
                        break;
                }

            }
        }

        private static void CreateClass(System.Text.StringBuilder sb, Field[] fields, int index)
        {
            string temp = "\t\t";

            for (int i = 0; i < index; i++)
            {
                temp += "\t";
            }

            foreach (var f in fields)
            {

                sb.AppendLine(temp + "/// <summary>");
                sb.AppendLine(temp + "/// " + (string.IsNullOrEmpty(f.Note) ? f.Comment : f.Note));
                if (f.Enum != null && f.Enum.Length > 0)
                {
                    sb.Append(temp + "/// ");
                    foreach (var e in f.Enum)
                    {
                        sb.Append(string.Format("{0}:{1} ", e.Key, e.Value));
                    }
                    sb.AppendLine();
                }
                sb.AppendLine(temp + "/// </summary>");
                sb.AppendLine(temp + string.Format("[Order({0})]", f.Sort));
                switch (f.Type)
                {
                    case "P":
                    case "S":
                        {
                            sb.AppendLine(temp + (f.CodeType == "APP" ? "public" : "internal") + " string " + f.Name + " { get; set; }");
                        }
                        break;
                    case "I":
                        {
                            sb.AppendLine(temp + (f.CodeType == "APP" ? "public" : "internal") + " int " + f.Name + " { get; set; }");
                        }
                        break;
                    case "E":
                        {
                            sb.AppendLine(temp + (f.CodeType == "APP" ? "public" : "internal") + " byte " + f.Name + " { get; set; }");
                        }
                        break;
                    case "F":
                        {
                            sb.AppendLine(temp + (f.CodeType == "APP" ? "public" : "internal") + " short " + f.Name + " { get; set; }");
                        }
                        break;
                    case "M"://签名
                        {
                            sb.AppendLine(string.Format(temp + (f.CodeType == "APP" ? "public" : "internal") + " string {0}", f.Name));
                            sb.AppendLine(temp + "{");
                            sb.AppendLine(temp + "\tget");
                            sb.AppendLine(temp + "\t{");
                            sb.AppendLine(temp + "\t\tList<string> values = new List<string>();");
                            sb.AppendLine(temp + "\t\tvalues.AddString(this.EventId);");
                            sb.AppendLine(temp + "\t\tvalues.AddString(this.TimeStamp);");
                            foreach (var item in fields)
                            {
                                switch (item.Type)
                                {
                                    case "M"://忽略
                                        break;
                                    case "K":
                                        sb.AppendLine(string.Format(temp + "\t\tvalues.AddString(this.{0});", item.Name + "Array.Length"));
                                        sb.AppendLine(string.Format(temp + "\t\tvalues.AddString(\"{0}\");", item.Loop.Length));
                                        sb.AppendLine(string.Format(temp + "\t\tforeach (var item in this.{0}Array)", item.Name));
                                        sb.AppendLine(temp + "\t\t{");
                                        sb.AppendLine(string.Format(temp + "\t\t//加入loop循环"));
                                        foreach (var i in item.Loop)
                                        {
                                            sb.AppendLine(string.Format(temp + "\t\t//加入{0}", i.Name));
                                            sb.AppendLine(string.Format(temp + "\t\t\tvalues.AddString(item.{0});", i.Name));
                                        }
                                        sb.AppendLine(temp + "\t\t}");
                                        break;
                                    default:
                                        sb.AppendLine(string.Format(temp + "\t\t//加入{0}", item.Name));
                                        sb.AppendLine(string.Format(temp + "\t\tvalues.AddString(this.{0});", item.Name));
                                        break;
                                }
                            }
                            sb.AppendLine(temp + "\t\treturn base.SignWithKVPair(values);");
                            sb.AppendLine(temp + "\t}");
                            sb.AppendLine(temp + "}");
                        }
                        break;
                    case "K"://循环
                        {
                            //生成对应的类
                            //string className = string.Format("{0}{1}", ClassName, f.Name);
                            sb.AppendLine(temp + "public " + f.Name + "[] " + f.Name + "Array { get; set; }");
                            sb.AppendLine(temp + "/// <summary>");
                            sb.AppendLine(temp + "/// " + f.Name + "类");
                            sb.AppendLine(temp + "/// </summary>");
                            sb.AppendLine(string.Format(temp + "public class {0}", f.Name));
                            sb.AppendLine(temp + "{");
                            //生成字段
                            CreateClass(sb, f.Loop, index + 1);

                            sb.AppendLine(temp + "}");
                        }
                        break;
                    default:
                        throw new Exception("未知类型");
                        break;
                }
            }
        }

        private void CreateCode()
        {
            System.Text.StringBuilder h = new System.Text.StringBuilder();
            System.Text.StringBuilder m = new System.Text.StringBuilder();
            h.Append(string.Format("/*\r\n事件名字：{0}\r\n埋点时机：{1}\r\n*/\r\n", Name, EventPoint));
            h.Append("#import <Foundation/Foundation.h>\r\n\r\n");
            h.Append(string.Format("@interface {0} : NSObject\r\n\r\n", FileName));

            m.Append("#import \"YK_BIEngine.h\"\r\n");
            m.Append(string.Format("#import \"{0}.h\"\r\n\r\n\r\n", FileName));
            m.Append(string.Format("@implementation {0}\r\n", FileName));
            foreach (var f in Fields)
            {
                h.Append(string.Format("@property(nonatomic,retain)NSString*         m_{0}; //{1}\r\n", f.Name, f.Note));
                m.Append(string.Format("@synthesize m_{0};\r\n", f.Name));
            }
            h.Append("\r\n");
            h.Append("-(BOOL)log; // 组装并发送事件，各个成员变量初始化好后调用,即完成事件的记录\r\n\r\n");
            h.Append("@end");

            m.Append("\r\n");
            m.Append("- (void)dealloc\r\n");
            m.Append("{\r\n");
            foreach (var f in Fields)
            {
                m.Append(string.Format("\t[m_{0} release];\r\n", f.Name));
            }
            m.Append("\r\n");
            m.Append("\t[super dealloc];\r\n");
            m.Append("}\r\n");
            m.Append("\r\n");
            m.Append("-(BOOL)log\r\n");
            m.Append("{\r\n");
            m.Append("\t// 创建事件对象\r\n");
            m.Append(string.Format("\tyk_BIEvent* event = [yk_BIEngine event:{0} type:0 priority:0];\r\n\r\n", this.Id));
            m.Append("\t// 写事件的各个字段\r\n");
            foreach (var f in Fields)
            {
                m.Append(string.Format("\t[event writeString:m_{0}];\r\n", f.Name));
            }
            m.Append("\r\n");
            m.Append("\t// 发送事件\r\n");
            m.Append("\treturn [yk_BIEngine logEvent:event];\r\n");
            m.Append("}\r\n");
            m.Append("\r\n");
            m.Append("@end");
            this.hfile = h.ToString();
            this.mfile = m.ToString();
        }
    }
}
